;s9-1.asm
assume cs:code
data segment
    db 'Welcome to masm!', 0        ;内存data段中定义一个字符串
data ends

code segment
    start:   ;字符串参数
        mov dh, 8           ;屏幕的行数
        mov dl, 77           ;所在行的列数
        mov ch, 0           ;ch清零，防止高8位不为零。
        mov cl, 2           ;颜色属性（此处应是二进制数0000 0010）

        mov ax, data
        mov ds, ax
        mov si, 0           ;将ds：si指向字符串
        call show_str

        mov ax, 4c00H
        int 21H
    ;show_str功能 :按行和列及字符属性显示字符串  
    ;入口参数：dh-行数、dl-列数、cl-字符属性、ds:[si]指向字符串。
    ;返回值：无
    
    show_str: 
        push dx
        push cx
        push si ;数据入栈保护

        mov ax,0B800H ;在汇编源程序中，数据不能以字母开头，所以要在前面加0。
        mov es,ax     ;显示缓冲区的段地址

        ;计算dl * 2 
        mov ax,0
        mov al,2
        mul dl
        mov bx,ax ;把结果放到dl

        ; 计算 dh * 160 结果在ax中
        mov ax,0   ;（ax）= 0，防止高位不为零  
        mov al,160 ;0a0H
        mul dh
        add bx,ax  ;获取最终否偏移量

        mov di,0   ;di作为字符的偏移零
        mov al,cl  ; 将属性放到al中，因为后边的程序会用到cx
    read:
        mov cl,ds:[si]
        mov ch,0             ;cx中 ch固定为零，关键在于cl的变化是否为零 
        jcxz ok              ;跳出，字符串操作完毕
        mov es:[bx+di+0],cl  ;对字符串业务操作 写入字符
        mov es:[bx+di+1],al  ; 写入属性
        inc si               ;下一个字符串
        add di,2        
        jmp short read       ;继续读取字符串
    ok:
        pop si 
        pop cx
        pop si
        ret

    code ends
    end start